package com.vic.bigdecimal;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * https://www.cnblogs.com/botaoli/p/12752911.html
 *
 * @author victor
 */
public class BigDecimalTest {

    public static void main(String[] args) {


        // 保留2位小数，四舍五入，并转换成百分率。
//        test6();

        // 保留2位小数，不四舍五入。
//        test5();


        // 保留2位小数，多于2位，则四舍五入后保留两位。
        // 方案3：String.format
//        test4_3();

        // 方案2：DecimalFormat
//        test4_2();

        // 方案1：手写
//        test4_1();


        // 打印小数点后有几位数
//        test3();

        // 比较 BigDecimal
//        test2();

        // 使用 BigDecimal 构造参数传 float 或 double 类型值的精度问题
//        test1();

    }


    /**
     * 保留2位小数，四舍五入，并转换成百分率。
     */
    private static void test6() {
        // #0.00% 表示保留两位小数，.后几个零就是保留几位小数，%号表示会转成百分率。
        DecimalFormat df2 = new DecimalFormat("#0.00%");

        List<BigDecimal> list = getBigDecimalList();
        for (BigDecimal amt : list) {
            System.out.println(df2.format(amt));
        }


        /*
        输出：
        0.00%
        0.00%
        0.00%
        0.00%
        -140.00%
        -131.50%
        -131.40%
        -100.00%
        -100.00%
        240.00%
        231.50%
        231.40%
        200.00%
        200.00%
         */
    }

    /**
     * 保留2位小数，不四舍五入。
     */
    private static void test5() {
        DecimalFormat df2 = new DecimalFormat("#0.00");
        df2.setRoundingMode(RoundingMode.DOWN);

        List<BigDecimal> list = getBigDecimalList();
        for (BigDecimal amt : list) {
//            System.out.println(df2.format(amt));

            // 或
            System.out.println(amt.setScale(2, BigDecimal.ROUND_DOWN));

        }




        /*
        输出：
        0.00
        0.00
        0.00
        0.00
        -1.40
        -1.31
        -1.31
        -1.00
        -1.00
        2.40
        2.31
        2.31
        2.00
        2.00
         */

    }


    /**
     * 保留2位小数，多于2位，则四舍五入后保留两位。
     * 方案3：String.format
     */
    private static void test4_3() {
        List<BigDecimal> list = getBigDecimalList();
        for (BigDecimal amt : list) {
            System.out.println(String.format("%.2f", amt));
        }
    }

    /**
     * 保留2位小数，多于2位，则四舍五入后保留两位。
     * 方案2：DecimalFormat
     */
    private static void test4_2() {
        DecimalFormat df2 = new DecimalFormat("0.00");

        List<BigDecimal> list = getBigDecimalList();
        for (BigDecimal amt : list) {
            System.out.println(df2.format(amt));
        }


        /*
        输出：
        0.00
        0.00
        0.00
        0.00

        -1.40
        -1.32
        -1.31
        -1.00
        -1.00

        2.40
        2.32
        2.31
        2.00
        2.00
         */

    }

    /**
     * 保留2位小数，多于2位，则四舍五入后保留两位。
     * 方案1：手写
     */
    private static void test4_1() {

        /*
         1. 0~1之间的BigDecimal小数，格式化后失去前面的0,则前面直接加上0。
         2. 传入的参数等于0，则直接返回字符串"0.00"
         3. 大于1的小数，直接格式化返回字符串
         */

        List<BigDecimal> list = getBigDecimalList();
        for (BigDecimal amt : list) {
            System.out.println(fmtAmtToTwoBit(amt.toString()));
        }


        /*
        输出：
        0.00
        0.00
        0.00
        0.00

        -1.40
        -1.32
        -1.31
        -1.00
        -1.00

        2.40
        2.32
        2.31
        2.00
        2.00
         */
    }

    public static String fmtAmtToTwoBit(String amtStr) {
        if(ObjectUtil.isNull(amtStr)) {
            return null;
        }
        if(StrUtil.isBlank(amtStr)) {
            return amtStr;
        }

        BigDecimal amt = new BigDecimal(amtStr);

        DecimalFormat df = new DecimalFormat("#.00");

        // 等于0
        if(amt.compareTo(BigDecimal.ZERO) == 0) {
            return "0.00";
        }else if(amt.compareTo(BigDecimal.ZERO) > 0 && amt.compareTo(new BigDecimal(1)) < 0) {
            // x > 0 && x < 1
            return "0"+df.format(amt).toString();
        }else if(amt.compareTo(BigDecimal.ZERO) < 0 && amt.compareTo(new BigDecimal(-1)) > 0) {
            // x < 0 && x > -1
            df = new DecimalFormat("0.00");
            return df.format(amt);
        }else {
            return df.format(amt);
        }
    }

    private static List<BigDecimal> getBigDecimalList() {

//        BigDecimal a1 = new BigDecimal("");
        BigDecimal a3 = new BigDecimal("0");
        BigDecimal a5 = new BigDecimal("0.");
        BigDecimal a7 = new BigDecimal("0.00");
        BigDecimal a9 = new BigDecimal("0.0");


        BigDecimal b1 = new BigDecimal("-1.4");
        BigDecimal b3 = new BigDecimal("-1.315");
        BigDecimal b5 = new BigDecimal("-1.314");
        BigDecimal b7 = new BigDecimal("-1"); // 和 -1. 一样
        BigDecimal b9 = new BigDecimal("-1.");

        BigDecimal c1 = new BigDecimal("2.4");
        BigDecimal c3 = new BigDecimal("2.315");
        BigDecimal c5 = new BigDecimal("2.314");
        BigDecimal c7 = new BigDecimal("2"); // 和 2. 一样
        BigDecimal c9 = new BigDecimal("2.");

        List<BigDecimal> list = new ArrayList<>();
//        list.add(a1);
        list.add(a3);
        list.add(a5);
        list.add(a7);
        list.add(a9);

        list.add(b1);
        list.add(b3);
        list.add(b5);
        list.add(b7);
        list.add(b9);

        list.add(c1);
        list.add(c3);
        list.add(c5);
        list.add(c7);
        list.add(c9);

        return list;
    }

    /**
     * 打印小数点后有几位数
     */
    private static void test3() {

        BigDecimal amt1 = new BigDecimal("-1.2");
        BigDecimal amt2 = new BigDecimal("1.27");
        BigDecimal amt3 = new BigDecimal("1.389");
        BigDecimal amt4 = new BigDecimal("1");

        System.out.println(amt1.scale());
        System.out.println(amt2.scale());
        System.out.println(amt3.scale());
        System.out.println(amt4.scale());
    }

    /**
     * 比较 BigDecimal
     */
    private static void test2() {

        // 0比较
        BigDecimal b = new BigDecimal("0");
        BigDecimal c = new BigDecimal("0.0");

        System.out.println(b.equals(c)); // false
        System.out.println(b.compareTo(c)); // 0
        System.out.println(b.compareTo(BigDecimal.ZERO)); // 0
        System.out.println(c.compareTo(BigDecimal.ZERO)); // 0


        //
        BigDecimal a1 = new BigDecimal("6.90");
        BigDecimal a2 = new BigDecimal("6.9");

        a1 = a1.setScale(2, BigDecimal.ROUND_HALF_UP);
        a2 = a2.setScale(2, BigDecimal.ROUND_HALF_UP);

        System.out.println(a1+" _");
        System.out.println(a2+" _");
//
        System.out.println(a1.compareTo(a2));
    }


    /**
     * 使用 BigDecimal 构造参数传 float 或 double 类型值的精度问题
     */
    private static void test1() {

        BigDecimal a = new BigDecimal(1.745);
        BigDecimal b = new BigDecimal(0.745);


        a = a.setScale(2, BigDecimal.ROUND_HALF_UP);
        b = b.setScale(2, BigDecimal.ROUND_HALF_UP);
        /*
        ROUND_HALF_UP 本意是绝对值后，往上四舍五入
        期望的结果：
        1.745 --> 1.75
        0.745 --> 0.75
         */

        // 1.75，与期望一致
        System.out.println("a: " + a);
        // 0.74，与期望不一致，精度丢失。
        System.out.println("a: " + b);

        /*
        运行以上代码可以看到，1.745四舍五入的结果是1.75，0.745四舍五入的结果是0.74。
        原因：
        使用参数为 float 或 double 的BigDecimal创建对象会丢失精度。因此强烈建议不要使用参数为float或double的BigDecimal创建对象。
         */

        System.out.println(new BigDecimal(1.745)); // 1.74500000000000010658141036401502788066864013671875
        System.out.println(new BigDecimal(0.745)); // 0.74499999999999999555910790149937383830547332763671875

        /*
        解决办法：
        1. 使用BigDecimal(String val)的构造方法创建对象
        new BigDecimal("1.745");
        new BigDecimal("0.745");
        2. 使用使用BigDecimal的valueOf(double val)方法创建对象
        BigDecimal.valueOf(1.745);
        BigDecimal.valueOf(0.745);
         */

        // 方法1
//        BigDecimal aa = new BigDecimal("1.745");
//        BigDecimal bb = new BigDecimal("0.745");
        // 方法2
        BigDecimal aa = BigDecimal.valueOf(1.745);
        BigDecimal bb = BigDecimal.valueOf(0.745);
        aa = aa.setScale(2, BigDecimal.ROUND_HALF_UP);
        bb = bb.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println("aa: " + aa); // 1.75
        System.out.println("aa: " + bb); // 0.75
    }
}
